/*
 * CC3Fog.m
 *
 * cocos3d 0.6.1
 * Author: Bill Hollings
 * Copyright (c) 2010-2011 The Brenwill Workshop Ltd. All rights reserved.
 * http://www.brenwill.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * http://en.wikipedia.org/wiki/MIT_License
 * 
 * See header file CC3Fog.h for full API documentation.
 */

#include "CC3Fog.h"
#include "CC3OpenGLES11Engine.h"
#include "CCActionManager.h"
#include "ccTypes.h"

CC3Fog::CC3Fog()
{
	isRunning = true;
	visible = true;
	floatColor = kCCC4FBlack;
	attenuationMode = GL_EXP2;
	performanceHint = GL_DONT_CARE;
	density = 1.0;
	startDistance = 0.0;
	endDistance = 1.0;
}

CC3Fog::~CC3Fog()
{
}

bool CC3Fog::getVisible()
{
	return visible;
}

void CC3Fog::setVisible(bool newValue)
{
	visible = newValue;
}

cocos2d::ccColor4F CC3Fog::getFloatColor()
{
	return floatColor;
}

void CC3Fog::setFloatColor(cocos2d::ccColor4F newValue)
{
	floatColor = newValue;
}

GLenum CC3Fog::getAttenuationMode()
{
	return attenuationMode;
}

void CC3Fog::setAttenuationMode(GLenum newValue)
{
	attenuationMode = newValue;
}

GLenum CC3Fog::getPerformanceHint()
{
	return performanceHint;
}

void CC3Fog::setPerformanceHint(GLenum newValue)
{
	performanceHint = newValue;
}

GLfloat CC3Fog::getDensity()
{
	return density;
}

void CC3Fog::setDensity(GLfloat newValue)
{
	density = newValue;
}

GLfloat CC3Fog::getStartDistance()
{
	return startDistance;
}

void CC3Fog::setStartDistance(GLfloat newValue)
{
	startDistance = newValue;
}

GLfloat CC3Fog::getEndDistance()
{
	return endDistance;
}

void CC3Fog::setEndDistance(GLfloat newValue)
{
	endDistance = newValue;
}

bool CC3Fog::getIsRunning()
{
	return isRunning;
}

void CC3Fog::setIsRunning(bool newValue)
{
	if (!isRunning && newValue) resumeActions();
	if (isRunning && !newValue) pauseActions();
	isRunning = newValue;
}

CC3Fog* CC3Fog::fog()
{
	CC3Fog* pFog = new CC3Fog;
	if (pFog) 
	{
		pFog->autorelease();
	}
	
	return pFog;
}

void CC3Fog::update(cocos2d::ccTime dt)
{
}

void CC3Fog::resumeActions()
{
	cocos2d::CCActionManager::sharedManager()->resumeTarget(this);
}

void CC3Fog::pauseActions()
{
	cocos2d::CCActionManager::sharedManager()->pauseTarget(this);
}

void CC3Fog::draw()
{
	if (visible) 
	{
		//LogTrace(@"Drawing %@", self);
		CC3OpenGLES11Engine* gles11Engine = CC3OpenGLES11Engine::engine();
		CC3OpenGLES11Fog* gles11Fog = gles11Engine->getFog();
		
		gles11Engine->getServerCapabilities()->getFog()->enable();
		gles11Engine->getHints()->getFog()->setValue(performanceHint);
		gles11Fog->getMode()->setValue(attenuationMode);
		gles11Fog->getColor()->setValue(floatColor);
		
		switch (attenuationMode) 
		{
			case GL_LINEAR:
				gles11Fog->getStart()->setValue(startDistance);
				gles11Fog->getEnd()->setValue(endDistance);
				break;
			case GL_EXP:
			case GL_EXP2:
				gles11Fog->getDensity()->setValue(density);
				break;
			default:
				//NSAssert2(NO, @"%@ encountered bad attenuation mode (%x)", self, attenuationMode);
				break;
		}
	} 
	else 
	{
		unbind();
	}
}

void CC3Fog::unbind()
{
	//LogTrace(@"Disabling fog");
	CC3OpenGLES11ServerCapabilities* pServerCapabilities = CC3OpenGLES11Engine::engine()->getServerCapabilities();
	if (pServerCapabilities && pServerCapabilities->getFog()) 
	{
		pServerCapabilities->getFog()->disable();
	}
}

cocos2d::CCAction* CC3Fog::runAction(cocos2d::CCAction* action)
{
	//NSAssert( action != nil, @"Argument must be non-nil");
	cocos2d::CCActionManager::sharedManager()->addAction(action, (cocos2d::CCNode*)this, !isRunning);
	return action;
}

void CC3Fog::stopAllActions()
{
	cocos2d::CCActionManager::sharedManager()->removeAllActionsFromTarget(this);
}

void CC3Fog::stopAction(cocos2d::CCAction* action)
{
	cocos2d::CCActionManager::sharedManager()->removeAction(action);
}

void CC3Fog::stopActionByTag(int aTag)
{
	//NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag");
	cocos2d::CCActionManager::sharedManager()->removeActionByTag(aTag, this);
}

cocos2d::CCAction* CC3Fog::getActionByTag(int aTag)
{
	//NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag");
	return cocos2d::CCActionManager::sharedManager()->getActionByTag(aTag, this);
}

int CC3Fog::numberOfRunningActions()
{
	return cocos2d::CCActionManager::sharedManager()->numberOfRunningActionsInTarget(this);
}

void CC3Fog::setColor(cocos2d::ccColor3B aColor)
{
	floatColor.r = CCColorFloatFromByte(aColor.r);
	floatColor.g = CCColorFloatFromByte(aColor.g);
	floatColor.b = CCColorFloatFromByte(aColor.b);
}

cocos2d::ccColor3B CC3Fog::getColor(void)
{
	return cocos2d::ccc3(CCColorByteFromFloat(floatColor.r),
				CCColorByteFromFloat(floatColor.g),
				CCColorByteFromFloat(floatColor.b));
}

GLubyte CC3Fog::getOpacity(void)
{
	return CCColorByteFromFloat(floatColor.a);
}

void CC3Fog::setOpacity(GLubyte opacity)
{
	floatColor.a = CCColorFloatFromByte(opacity);
}

//@interface CC3Fog (TemplateMethods)
//	-(void) resumeActions;
//	-(void) pauseActions;
//@end
//
//
//@implementation CC3Fog
//
//@synthesize isRunning, visible, floatColor, attenuationMode, performanceHint;
//@synthesize density, startDistance, endDistance;
//
//-(void) setIsRunning: (BOOL) shouldRun {
//	if (!isRunning && shouldRun) [self resumeActions];
//	if (isRunning && !shouldRun) [self pauseActions];
//	isRunning = shouldRun;
//}
//
//
//#pragma mark Allocation and initialization
//
//-(id) init {
//	if ( (self = [super init]) ) {
//		isRunning = YES;
//		visible = YES;
//		floatColor = kCCC4FBlack;
//		attenuationMode = GL_EXP2;
//		performanceHint = GL_DONT_CARE;
//		density = 1.0;
//		startDistance = 0.0;
//		endDistance = 1.0;
//	}
//	return self;
//}
//
//+(id) fog {
//	return [[[self alloc] init] autorelease];
//}
//
//// Template method that populates this instance from the specified other instance.
//// This method is invoked automatically during object copying via the copyWithZone: method.
//-(void) populateFrom: (CC3Fog*) another {
//	isRunning = another.isRunning;
//	visible = another.visible;
//	floatColor = another.floatColor;
//	attenuationMode = another.attenuationMode;
//	performanceHint = another.performanceHint;
//	density = another.density;
//	startDistance = another.startDistance;
//	endDistance = another.endDistance;
//}
//
//-(id) copyWithZone: (NSZone*) zone {
//	CC3Fog* aCopy = [[[self class] allocWithZone: zone] init];
//	[aCopy populateFrom: self];
//	return aCopy;
//}
//
//
//#pragma mark Updating
//
//-(void) update: (ccTime)dt {}
//
//
//#pragma mark Drawing
//
//-(void) draw {
//	if (visible) {
//		LogTrace(@"Drawing %@", self);
//		CC3OpenGLES11Engine* gles11Engine = [CC3OpenGLES11Engine engine];
//		CC3OpenGLES11Fog* gles11Fog = gles11Engine.fog;
//
//		[gles11Engine.serverCapabilities.fog enable];
//		gles11Engine.hints.fog.value = performanceHint;
//		gles11Fog.mode.value = attenuationMode;
//		gles11Fog.color.value = floatColor;
//
//		switch (attenuationMode) {
//			case GL_LINEAR:
//				gles11Fog.start.value = startDistance;
//				gles11Fog.end.value = endDistance;
//				break;
//			case GL_EXP:
//			case GL_EXP2:
//				gles11Fog.density.value = density;
//				break;
//			default:
//				NSAssert2(NO, @"%@ encountered bad attenuation mode (%x)", self, attenuationMode);
//				break;
//		}
//	} else {
//		[self unbind];
//	}
//}
//
//-(void) unbind {
//	[[self class] unbind];
//}
//
//+(void) unbind {
//	LogTrace(@"Disabling fog");
//	[[CC3OpenGLES11Engine engine].serverCapabilities.fog disable];
//}
//
//
//#pragma mark CCRGBAProtocol support
//
///** Returns the value of the color property converted from float to integer components. */
//-(ccColor3B) color {
//	return ccc3(CCColorByteFromFloat(floatColor.r),
//				CCColorByteFromFloat(floatColor.g),
//				CCColorByteFromFloat(floatColor.b));
//}
//
///** Sets the color property by converting the specified integer color components to floats. */
//-(void) setColor: (ccColor3B) aColor {
//	floatColor.r = CCColorFloatFromByte(aColor.r);
//	floatColor.g = CCColorFloatFromByte(aColor.g);
//	floatColor.b = CCColorFloatFromByte(aColor.b);
//}
//
///** Returns the alpha component from the color property converted from a float to an integer. */
//-(GLubyte) opacity {
//	return CCColorByteFromFloat(floatColor.a);
//}
//
///** Sets the alpha component of the color property by converting the specified integer opacity to a float. */
//-(void) setOpacity: (GLubyte) opacity {
//	floatColor.a = CCColorFloatFromByte(opacity);
//}
//
//-(NSString*) description {
//	return [NSString stringWithFormat: @"%@", [self class]];
//}
//
//
//#pragma mark CC3Node Actions
//
//-(CCAction*) runAction:(CCAction*) action {
//	NSAssert( action != nil, @"Argument must be non-nil");
//	[[CCActionManager sharedManager] addAction: action target: self paused: !isRunning];
//	return action;
//}
//
//-(void) stopAllActions {
//	[[CCActionManager sharedManager] removeAllActionsFromTarget: self];
//}
//
//-(void) stopAction: (CCAction*) action {
//	[[CCActionManager sharedManager] removeAction: action];
//}
//
//-(void) stopActionByTag:(int)aTag {
//	NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag");
//	[[CCActionManager sharedManager] removeActionByTag: aTag target: self];
//}
//
//-(CCAction*) getActionByTag:(int) aTag {
//	NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag");
//	return [[CCActionManager sharedManager] getActionByTag: aTag target: self];
//}
//
//-(int) numberOfRunningActions {
//	return [[CCActionManager sharedManager] numberOfRunningActionsInTarget: self];
//}
//
//- (void) resumeActions {
//	[[CCActionManager sharedManager] resumeTarget: self];
//}
//
//- (void) pauseActions {
//	[[CCActionManager sharedManager] pauseTarget: self];
//}
//
//@end
